/**
 * 
 */
package com.netscenery.yang.model;

import java.util.ArrayList;

import org.jdom2.Attribute;
import org.jdom2.Element;

import com.netscenery.util.QName;
import com.netscenery.util.XMLTag;
import com.netscenery.yang.YangKeyword;
import com.netscenery.yang.YangStatement;
import com.netscenery.yang.designer.MapInfo;
import com.netscenery.yang.parser.YangParserException;

/**
 * @author yanzi
 *
 */
public class Rpc extends Entity {
	private ArrayList<String> if_features;
	private ArrayList<Typedef> typedefs;
	private ArrayList<Grouping> groupings;
	private Input input;
	private Output output;
	

	/**
	 * 
	 */
	public Rpc() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * @param env
	 * @param name
	 * @throws ModelException 
	 */
	public Rpc(Env env, String name) throws ModelException {
		super(env, name);
		// TODO Auto-generated constructor stub
	}

	/**
	 * @param env
	 * @param qname
	 */
	public Rpc(Env env, QName qname) {
		super(env, qname);
		// TODO Auto-generated constructor stub
	}

	
	
	/**
	 * ��ȡgrouping����Ŀ
	 * @return
	 * @see com.netscenery.model.Grouping
	 */
	public int getGroupingsNumber(){
		if (null == this.groupings){
			return 0;
		}
		return this.groupings.size();
	}
	/**
	 * ���ָ������ƴ���grouping
	 * @param name
	 * @return
	 * @throws ModelException 
	 * @see com.netscenery.model.Grouping
	 */
	public Grouping createGrouping(String name) throws ModelException{
		if (null == name){
			return null;
		}
		
		return new Grouping(newSubEnv(),name);
	}
	/**
	 * ���һ��grouping
	 * @param n
	 * @return
	 * @see com.netscenery.model.Grouping
	 */
	public boolean addGrouping(Grouping n){
		if(null == n){
			return false;
		}
		
		if (null == this.groupings){
			this.groupings = new ArrayList<Grouping>(1);
		}
		if (null != this.getGrouping(n.getName())){
			return false;
		}
		return this.groupings.add(n);
		

	}
	/**
	 * �����Ż�ȡGrouping
	 * @param index
	 * @return
	 * @see com.netscenery.model.Grouping
	 */
	public Grouping getGrouping(int index){
		if (null == this.groupings){
			return null;
		}
		if (index >= this.groupings.size()){
			return null;
		}
		return this.groupings.get(index);
	}
	/**
	 * �����ƻ�ȡGrouping
	 * @param name
	 * @return
	 * @see com.netscenery.model.Grouping
	 */
	public Grouping getGrouping(String name){
		if (null == this.groupings){
			return null;
		}
		int size = groupings.size();
		if (size <= 0){
			return null;
		}
		
		for (int i = 0; i < size; i++){
			Grouping n = this.groupings.get(i);
			if (null != n){
				if (n.getName().equals(name)){
					return n;
				}
			}
		}
		return null;
	}
	/**
	 * ������ɾ��Grouping
	 * @param index
	 * @return Grouping
	 * @see com.netscenery.model.Grouping
	 */
	public Grouping removeGrouping(int index){
		if (null == this.groupings){
			return null;
		}
		if (index >= this.groupings.size()){
			return null;
		}
		return this.groupings.remove(index);
	}
	/**
	 * ������ɾ��Grouping
	 * @param name
	 * @return Grouping
	 * @see com.netscenery.model.Grouping
	 */
	public Grouping removeGrouping(String name){
		if (null == this.groupings){
			return null;
		}
		int size = groupings.size();
		if (size <= 0){
			return null;
		}
		
		
		for (int i = 0; i < size; i++){
			Grouping n = this.groupings.get(i);
			if (null != n){
				if (n.getName().equals(name)){
					return groupings.remove(i);
				}
			}
		}
		return null;
	}

	
	/**
	 * �����ƴ���һ��typedef
	 * @param name
	 * @return
	 * @see com.netscenery.model.Typedef
	 */
	public Typedef createTypedef(String name){
		if (null == name){
			return null;
		}
		
		return new Typedef(newSubEnv(),name);
	}
	/**
	 * ���һ��typedef
	 * @param def
	 * @return
	 * @see com.netscenery.model.Typedef
	 */
	public boolean addTypedef(Typedef def){
		if(null == def){
			return false;
		}
		
		if (null == this.typedefs){
			this.typedefs = new ArrayList<Typedef>(1);
		}
		this.typedefs.add(def);
		Env env = this.getEnv();
		env.addDerivedType(def);
		return true;
	}
	/**
	 * �����Ż�ȡtypedef
	 * @param index
	 * @return
	 * @see com.netscenery.model.Typedef
	 */
	public Typedef getTypedef(int index){
		if (null == this.typedefs){
			return null;
		}
		if (index >= this.typedefs.size()){
			return null;
		}
		return this.typedefs.get(index);
	}
	/**
	 * ���typedef��ƻ�ȡtypedef
	 * @param defName
	 * @return
	 * @see com.netscenery.model.Typedef
	 */
	public Typedef getTypedef(String defName){
		if (null == this.typedefs){
			return null;
		}
		int size = typedefs.size();
		if (size <= 0){
			return null;
		}
		
		for (int i = 0; i < size; i++){
			Typedef def = this.typedefs.get(i);
			if (null != def){
				if (def.getName().equals(defName)){
					return def;
				}
			}
		}
		return null;
	}
	/**
	 * ������ɾ��typedef
	 * @param index
	 * @return
	 * @see com.netscenery.model.Typedef
	 */
	public Typedef removeTypedef(int index){
		if (null == this.typedefs){
			return null;
		}
		if (index >= this.typedefs.size()){
			return null;
		}
		return this.typedefs.remove(index);
	}
	/**
	 * ������ɾ��typedef
	 * @param defName
	 * @return
	 */
	public Typedef removeTypedef(String defName){
		if (null == this.typedefs){
			return null;
		}
		int size = typedefs.size();
		if (size <= 0){
			return null;
		}
		
		for (int i = 0; i < size; i++){
			Typedef def = this.typedefs.get(i);
			if (null != def){
				if (def.getName().equals(defName)){
					return typedefs.remove(i);
				}
			}
		}
		return null;
	}
	/**
	 * ��ȡtypedef�ĸ���
	 * @return
	 */
	public int getTypedefsNumber(){
		if (null == this.typedefs){
			return 0;
		}
		return this.typedefs.size();
	}
	public boolean checkIf_feature(String feature){
		if (null == feature){
			return false;
		}
		Module m = env.getCurModule();
		if (null == m){
			return false;
		}
		QName qFeature = new QName(feature);
		if (qFeature.isQName()){
			String prefix = qFeature.getPrefix();
			String localName = qFeature.getLocalName();
			if (null == prefix || null == localName){
				return false;
			}
			Module imp = m.getModule(prefix);
			if (null == imp ){
				return false;
			}
			
			if (null == imp.getFeature(localName)){
				return false;
			}
	
		}
		else {
			if (null == m.getFeature(feature)){
				return false;
			}
		}
		return true;
	}
	public boolean addIf_feature(String feature){
		if (null == feature){
			return false;
		}
		if (false == checkIf_feature(feature)){
			return false;
		}
		if (null == if_features){
			if_features = new ArrayList<String>(1);
		}
		return if_features.add(feature);
	}
	
	public String getIf_feature(int index){
		if (null == if_features){
			return null;
		}
		return if_features.get(index);
	}
	
	public String removeIf_feature(int index){
		if (null == if_features){
			return null;
		}
		return if_features.remove(index);
	}
	
	public int getIf_featuresNumber(){
		if (null == if_features){
			return 0;
		}
		
		return if_features.size();
	}

	public Input getInput() {
		return input;
	}

	public void setInput(Input input) {
		this.input = input;
	}

	public Output getOutput() {
		return output;
	}

	public void setOutput(Output output) {
		this.output = output;
	}

	
	@Override
	public YangStatement toYang() {
		YangStatement rpc = new YangStatement(YangKeyword.RPC.getKeyword(),this.name);
		
		if (null != if_features){
			int size = this.getIf_featuresNumber();
			
			for (int i = 0; i < size; i++){
				String feature = this.getIf_feature(i);
				if (null != feature){
					YangStatement  featureState = 
							new YangStatement(
									YangStatement.YANG_STATEMENT_IFFEATURE
							        ,feature);
					rpc.addChild(featureState);
				}
			}
		
		}
		if (!isNullString(this.getDescription())){
			YangStatement descr = new YangStatement(YangKeyword.DESCRIPTION.getKeyword(),this.getDescription());
			rpc.addChild(descr);
		}
		if (null != this.getReference()){
			YangStatement ref = new YangStatement(YangStatement.YANG_STATEMENT_REFERENCE,this.getReference());
			rpc.addChild(ref);
		}
		
		if (Status.CURRENT != this.getStatus()){
			YangStatement status = new YangStatement(YangStatement.YANG_STATEMENT_STATUS,this.getStatus().getStatus());
			rpc.addChild(status);
		}


		if (null != typedefs){
			int size = this.getTypedefsNumber();
			for (int i = 0; i < size; i++){
				Typedef def = this.getTypedef(i);
				if (null != def){
					YangStatement defstat = def.writeYang();
					if (null == defstat){
						continue;
					}
					rpc.addChild(defstat);
				}
			}
		}
		
		/*
		 * groupings
		 */
		if (null != this.groupings){
			int size = this.getGroupingsNumber();
			for (int i = 0; i < size; i++){
				Grouping grp = this.getGrouping(i);
				if (null != grp){
					YangStatement grpstat = grp.writeYang();
					if (null == grpstat){
						continue;
					}
					rpc.addChild(grpstat);
				}
			}
		}
		
		if (null != input){
			YangStatement inputStat = input.toYang();
			if (null != inputStat){
				rpc.addChild(inputStat);
			}
		}
		
		if (null != output){
			YangStatement outputStat = output.toYang();
			if (null != outputStat){
				rpc.addChild(outputStat);
			}
		}
		
		return rpc;
	}



	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#toYin()
	 */
	@Override
	public Element toYin() {
		Element element = new Element(YangKeyword.RPC.getKeyword(),env.getNs());
		Attribute name = new Attribute("name",this.name);
		element.setAttribute(name);
		
		
		if (null != this.if_features){
			int size = this.getIf_featuresNumber();
			
			for (int i = 0; i < size; i++){
				String feature = this.getIf_feature(i);
				if (null != feature){
					Element  featureState = 
							new Element(YangKeyword.IFFEATURE.getKeyword(),env.getNs());
					Attribute fname = new Attribute(XMLTag.XML_TAG_NAME,feature);
					featureState.setAttribute(fname);
					element.addContent(featureState);
				}
			}
			
		}
		
		if (!isNullString(this.getDescription())){
			Element descr = new Element(YangStatement.YANG_STATEMENT_DESCRIPTION,env.getNs());
			Element text = new Element(XMLTag.XML_TAG_TEXT,env.getNs());
			text.setText(this.getDescription());
			descr.addContent(text);
			element.addContent(descr);
		}
		if (null != this.getReference()){
			Element ref = new Element(YangStatement.YANG_STATEMENT_REFERENCE,env.getNs());
			Element text = new Element(XMLTag.XML_TAG_TEXT,env.getNs());
			text.setText(this.getReference());
			ref.addContent(text);
			element.addContent(ref);
		}
		
		if (Status.CURRENT != this.getStatus()){
			Element status = new Element(YangStatement.YANG_STATEMENT_STATUS,env.getNs());
			Attribute value = new Attribute(YangKeyword.VALUE.getKeyword(),this.getStatus().getStatus());
			status.setAttribute(value);
			element.addContent(status);
		}
		
		/*
		 * typedefs
		 */
		if (null != this.typedefs){
			int size = this.getTypedefsNumber();
			for (int i = 0; i < size; i++){
				Typedef def = this.getTypedef(i);
				if (null != def){
					Element defstat = def.writeYin();
					if (null == defstat){
						continue;
					}
					element.addContent(defstat);
				}
			}
		}
		/*
		 * groupings
		 */
		if (null != this.groupings){
			int size = this.getGroupingsNumber();
			for (int i = 0; i < size; i++){
				Grouping grp = this.getGrouping(i);
				if (null != grp){
					Element grpstat = grp.writeYin();
					if (null == grpstat){
						continue;
					}
					element.addContent(grpstat);
				}
			}
		}

		return element;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#toXML()
	 */
	@Override
	public Element toXML() {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#readXML(org.jdom2.Element)
	 */
	@Override
	public int readXML(Element element) throws ModelException {
		// TODO Auto-generated method stub
		return 0;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#readYin(org.jdom2.Element)
	 */
	@Override
	public int readYin(Element statement) throws ModelException {
		if (null== statement){
			return MODELELEMENT_OK;
		}
		int superRes = super.readYin(statement);
		if (MODELELEMENT_NOTFOUND != superRes){
			return superRes;
		}
		
		// if-feature
		if (statement.getName().equals(
				YangStatement.YANG_STATEMENT_IFFEATURE)) {
			String value= statement.getAttributeValue(XMLTag.XML_TAG_NAME);
			this.addIf_feature(value);
		}
		/*
		 * typedefs
		 */
		else if (statement.getName().equals(YangStatement.YANG_STATEMENT_TYPEDEF)){

			Env subEnv = newSubEnv();
			Typedef ext = (Typedef) ModelElement.parseYin(subEnv, statement);
			this.addTypedef(ext);
		}
		/*
		 * groupings
		 */
		else if (statement.getName().equals(YangStatement.YANG_STATEMENT_GROUPING)){

			Env subEnv = newSubEnv();
			Grouping ext = (Grouping) ModelElement.parseYin(subEnv, statement);
			this.addGrouping(ext);
		}
		else if (statement.getName().equals(YangKeyword.INPUT.getKeyword())){
			Input in= (Input) ModelElement.parseYin(newSubEnv(), statement);
			this.setInput(in);
		}
		else if (statement.getName().equals(YangKeyword.OUTPUT.getKeyword())){
			Output out= (Output) ModelElement.parseYin(newSubEnv(), statement);
			this.setOutput(out);
		}
		else {
			return MODELELEMENT_FAIL;
		}
		
		return MODELELEMENT_OK;
	}




	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#readYANG(com.netscenery.yang.YangStatement)
	 */
	@Override
	public int readYANG(YangStatement statement) throws YangParserException, ModelException {
		if (null== statement){
			return MODELELEMENT_OK;
		}
		int superRes = super.readYANG(statement);
		if (MODELELEMENT_NOTFOUND != superRes){
			return superRes;
		}
		String value = statement.getArgument();
		// if-feature
		if (statement.getKeyword().equals(
				YangStatement.YANG_STATEMENT_IFFEATURE)) {
			this.addIf_feature(value);
		}
		/*
		 * typedefs
		 */
		else if (statement.getKeyword().equals(YangStatement.YANG_STATEMENT_TYPEDEF)){
	
			Env subEnv = newSubEnv();
			Typedef ext = (Typedef) ModelElement.parseYANG(subEnv, statement);
			this.addTypedef(ext);
		}
		/*
		 * groupings
		 */
		else if (statement.getKeyword().equals(YangStatement.YANG_STATEMENT_GROUPING)){
	
			Env subEnv = newSubEnv();
			Grouping ext = (Grouping) ModelElement.parseYANG(subEnv, statement);
			this.addGrouping(ext);
		}
		else if (statement.getKeyword().equals(YangKeyword.INPUT.getKeyword())){
			Input in= (Input) ModelElement.parseYANG(newSubEnv(), statement);
			this.setInput(in);
		}
		else if (statement.getKeyword().equals(YangKeyword.OUTPUT.getKeyword())){
			Output out= (Output) ModelElement.parseYANG(newSubEnv(), statement);
			this.setOutput(out);
		}
		else {
			return MODELELEMENT_FAIL;
		}
		
		return MODELELEMENT_OK;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#isFieldMandatory(java.lang.String)
	 */
	@Override
	public boolean isFieldMandatory(String field) {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.ModelElement#getMapInfo()
	 */
	@Override
	public MapInfo getMapInfo() throws SecurityException, NoSuchMethodException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void update() {
		// TODO Auto-generated method stub
		
	}

}
